package info.liuxing.okhttp;

import info.liuxing.okhttp.cookie.MemoryCookieStore;
import info.liuxing.okhttp.dns.CustomDns;
import info.liuxing.okhttp.interceptor.DefaultHeadersInterceptor;
import info.liuxing.okhttp.interceptor.DynamicSetTimeoutInterceptor;
import info.liuxing.okhttp.interceptor.LoggingInterceptor;
import info.liuxing.okhttp.listener.PrintingEventListener;
import info.liuxing.okhttp.proxy.CustomProxySelector;
import info.liuxing.okhttp.ssl.TrustAllHostnameVerifier;
import info.liuxing.okhttp.ssl.TrustAllManager;
import okhttp3.*;
import okhttp3.internal.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.File;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * OkHttpUtil
 *
 * @author liuxing (SE)
 * @summary OkHttpUtil
 * @Copyright (c) 2017, Lianjia Group All Rights Reserved.
 * @since 2017-11-10 17:42
 */
public class OkHttpUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(OkHttpUtil.class);

    public static OkHttpClient client;

    static {
        OkHttpClient.Builder build = new OkHttpClient.Builder()
                // 失败后重试，默认true
                .retryOnConnectionFailure(true)
                // 读取超时 默认 10秒
                .readTimeout(10, TimeUnit.SECONDS)
                // 写入超时 默认 10秒
                .writeTimeout(10, TimeUnit.SECONDS)
                // 连接超时 默认 10秒
                .connectTimeout(5, TimeUnit.SECONDS)
                // 连接池 默认是ConnectionPool的构造设置
                .connectionPool(new ConnectionPool(50, 10, TimeUnit.MINUTES))
                // 心跳时间 默认0，不检测
                .pingInterval(5, TimeUnit.SECONDS)
                // 动态设置超时时间
                .addInterceptor(new DynamicSetTimeoutInterceptor())
                // 请求日志拦截器
                .addInterceptor(new LoggingInterceptor())
                // 默认header
                .addInterceptor(new DefaultHeadersInterceptor());

        ExecutorService executor = new ThreadPoolExecutor(50, 200, 10, TimeUnit.MINUTES,
                new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));

        // 调度线程池
        Dispatcher dispatcher = new Dispatcher(executor);
        dispatcher.setMaxRequests(1000);
        dispatcher.setMaxRequestsPerHost(1000);

        build.dispatcher(dispatcher);

        // ssl
        build.sslSocketFactory(createSSLSocketFactory(), new TrustAllManager());
        build.hostnameVerifier(new TrustAllHostnameVerifier());

        // cookie管理
        build.cookieJar(new MemoryCookieStore());

        // DNS
        build.dns(new CustomDns());

        // 设置代理
//        build.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 11087)));
//        build.proxyAuthenticator()

        // 设置代理选择器
        build.proxySelector(new CustomProxySelector());

        // 事件监听
        build.eventListener(new PrintingEventListener());
        build.cache(new Cache(new File(""), 1000));
        client = build.build();
    }

    public static OkHttpClient client() {
        return client;
    }

    /**
     * GET请求
     *
     * @param url
     * @return
     */
    public static String doGet(String url) {
        Request request = new Request.Builder()
                .url(url)
                .build();
        try {
            try (Response response = client.newCall(request).execute()) {
                return response.body().string();
            }

        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
        }

        return null;
    }

    /**
     * POST请求
     *
     * @param url
     * @param mediaType
     * @param content
     * @return
     */
    public static String doPost(String url, MediaType mediaType, String content) {
        RequestBody body = RequestBody.create(mediaType, content);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();

        try {
            try (Response response = client.newCall(request).execute()) {
                return response.body().string();
            }
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
        }

        return null;
    }

    /**
     * json
     */
    public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");
    /**
     * html
     */
    public static final MediaType MEDIA_TYPE_TEXT_HTML = MediaType.parse("text/html; charset=utf-8");
    /**
     * 纯文本
     */
    public static final MediaType MEDIA_TYPE_TEXT_PLAIN = MediaType.parse("text/plain; charset=utf-8");
    /**
     * 表单
     */
    public static final MediaType MEDIA_TYPE_FORM_URLENCODED = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");
    /**
     * 文件上传
     */
    public static final MediaType MEDIA_TYPE_FORM_DATA = MediaType.parse("multipart/form-data; charset=utf-8");

    /**
     * 默认信任所有的证书
     * TODO 最好加上证书认证，主流App都有自己的证书
     *
     * @return
     */
    private static SSLSocketFactory createSSLSocketFactory() {

        SSLSocketFactory sSLSocketFactory = null;

        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[]{new TrustAllManager()}, new SecureRandom());
            sSLSocketFactory = sc.getSocketFactory();
        } catch (Exception e) {
        }

        return sSLSocketFactory;
    }

}
